Skip to content

Conversation

@Pearl1594
Copy link
Contributor

Description

This PR fixes: #10305
Currently when the global setting 'user.vm.readonly.details' is cleared, it sets the global setting value to NULL. Querying a global setting whose value is null returns the default value. Hence, updating this specific global setting value to "" as opposed to NULL.

Types of changes

  • Breaking change (fix or feature that would cause existing functionality to change)
  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Enhancement (improves an existing feature and functionality)
  • Cleanup (Code refactoring and cleanup, that may add test cases)
  • build/CI
  • test (unit or integration test code)

Feature/Enhancement Scale or Bug Severity

Feature/Enhancement Scale

  • Major
  • Minor

Bug Severity

  • BLOCKER
  • Critical
  • Major
  • Minor
  • Trivial

Screenshots (if appropriate):

How Has This Been Tested?

How did you try to break this feature and the system with this change?

@codecov
Copy link

codecov bot commented Feb 24, 2025

Codecov Report

❌ Patch coverage is 71.42857% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 4.03%. Comparing base (5c1f931) to head (7707ca5).
⚠️ Report is 21 commits behind head on 4.20.

Files with missing lines Patch % Lines
.../apache/cloudstack/framework/config/ConfigKey.java 71.42% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##               4.20   #10456       +/-   ##
=============================================
- Coverage     16.23%    4.03%   -12.21%     
=============================================
  Files          5657      402     -5255     
  Lines        498996    32701   -466295     
  Branches      60566     5826    -54740     
=============================================
- Hits          81011     1319    -79692     
+ Misses       408951    31227   -377724     
+ Partials       9034      155     -8879     
Flag Coverage Δ
uitests 4.03% <ø> (ø)
unittests 17.09% <71.42%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sonarqubecloud
Copy link

@Pearl1594 Pearl1594 linked an issue Feb 25, 2025 that may be closed by this pull request
@Pearl1594
Copy link
Contributor Author

@blueorangutan package

@blueorangutan
Copy link

@Pearl1594 a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

@weizhouapache
Copy link
Member

@Pearl1594
would be good to add a parameter to ConfigKey to indicate whether use default value if empty ?

@Pearl1594
Copy link
Contributor Author

@Pearl1594 would be good to add a parameter to ConfigKey to indicate whether use default value if empty ?

Currently when value is null, it picks up the default value, but in this case, we do not want it to use the default value. Unless I understood you wrong @weizhouapache

@DaanHoogland
Copy link
Contributor

@Pearl1594 would be good to add a parameter to ConfigKey to indicate whether use default value if empty ?

Currently when value is null, it picks up the default value, but in this case, we do not want it to use the default value. Unless I understood you wrong @weizhouapache

Yes, @Pearl1594 , but I think it is still good to use a ConfigKey and let users set it explicitely to "".

@weizhouapache
Copy link
Member

@Pearl1594 would be good to add a parameter to ConfigKey to indicate whether use default value if empty ?

Currently when value is null, it picks up the default value, but in this case, we do not want it to use the default value. Unless I understood you wrong @weizhouapache

@Pearl1594 would be good to add a parameter to ConfigKey to indicate whether use default value if empty ?

Currently when value is null, it picks up the default value, but in this case, we do not want it to use the default value. Unless I understood you wrong @weizhouapache

Yes, @Pearl1594 , but I think it is still good to use a ConfigKey and let users set it explicitely to "".

yes. using ConfigKey is more generic, it is easier to support more configurations in the future, for example user.vm.denied.details.

@blueorangutan
Copy link

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ debian ✔️ suse15. SL-JID 12576

@Pearl1594 Pearl1594 marked this pull request as draft April 9, 2025 19:45
@sureshanaparti sureshanaparti added this to the 4.19.4 milestone Jun 5, 2025
@DaanHoogland DaanHoogland force-pushed the readonly-vm-details-empty branch from a970680 to dec53f7 Compare August 20, 2025 15:15
@sonarqubecloud
Copy link

@weizhouapache weizhouapache modified the milestones: 4.19.4, 4.20.2 Sep 2, 2025
@weizhouapache weizhouapache modified the milestones: 4.20.2, 4.20.3 Sep 11, 2025
@DaanHoogland
Copy link
Contributor

@Pearl1594 , can you revisit?

@Pearl1594
Copy link
Contributor Author

Will look into it tomorrow @DaanHoogland .

@github-actions
Copy link

This pull request has merge conflicts. Dear author, please fix the conflicts and sync your branch with the base branch.

@Pearl1594 Pearl1594 changed the base branch from 4.22 to 4.20 January 14, 2026 19:56
Copy link
Contributor

@DaanHoogland DaanHoogland left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clgtm, we might want to look at contingency on the number of constructors as well (not in this PR)

@Pearl1594
Copy link
Contributor Author

@blueorangutan package

@blueorangutan
Copy link

@Pearl1594 a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 16383

@Pearl1594
Copy link
Contributor Author

@blueorangutan test

@blueorangutan
Copy link

@Pearl1594 a [SL] Trillian-Jenkins test job (ol8 mgmt + kvm-ol8) has been kicked to run smoke tests

@blueorangutan
Copy link

[SF] Trillian Build Failed (tid-15194)

@DaanHoogland
Copy link
Contributor

@shwstppr @Pearl1594 , does this still need work? (i.e. the status:needs-work label!)

Copy link
Collaborator

@RosiKyu RosiKyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

All 6 test cases passed - empty user.vm.readonly.details now correctly allows users to modify all VM details instead of falling back to default values. LGTM

Test Execution Summary

Test Case Description Status
TC1 Default behavior – readonly details blocked for users PASS
TC2 Empty setting allows all VM detail modifications PASS
TC3 Custom readonly details are enforced PASS
TC4 Root Admin can always modify all details PASS
TC5 Bogus value workaround still works PASS
TC6 Setting persists after MS restart PASS

Detailed Test Report

TC1: Verify default behavior with default setting value

Objective:
Confirm that with default settings, specified VM details (dataDiskController, rootDiskController) remain read-only for non-root users while custom details can be modified.

Test Steps:

  1. Verified user.vm.readonly.details is set to default value: dataDiskController, rootDiskController
  2. Deployed a VM as regular User (ACSUser account)
  3. Attempted to modify dataDiskController detail on the VM
  4. Attempted to modify rootDiskController detail on the VM
  5. Attempted to add a custom detail customDetail on the VM

Expected Result:

  • Modifications to dataDiskController and rootDiskController should be BLOCKED
  • Modification to custom detail should be ALLOWED

Actual Result:

  • Modifications to dataDiskController and rootDiskController were BLOCKED with error 4250
  • Custom detail customDetail was successfully added ✓

Test Evidence:

(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].dataDiskController=ide
🙈 Error: (HTTP 530, error code 4250) Internal error executing command, please contact your system administrator

(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].rootDiskController=ide
🙈 Error: (HTTP 530, error code 4250) Internal error executing command, please contact your system administrator

(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].customDetail=testvalue
{
  "virtualmachine": {
    "account": "ACSUser",
    "affinitygroup": [],
    "cpunumber": 1,
    "cpuspeed": 500,
    "cpuused": "0%",
    "created": "2026-01-26T07:37:11+0000",
    "deleteprotection": false,
    "details": {
      "customDetail": "testvalue"
    },
    "diskioread": 0,
    "diskiowrite": 0,
    "diskkbsread": 0,
    "diskkbswrite": 0,
    "displayname": "user-vm-1",
    "domain": "ROOT",
    "domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
    "domainpath": "/",
    "guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "haenable": false,
    "hasannotations": false,
    "hostcontrolstate": "Enabled",
    "hypervisor": "KVM",
    "id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
    "ipaddress": "10.1.1.189",
    "isdynamicallyscalable": false,
    "lastupdated": "2026-01-26T07:38:21+0000",
    "memory": 512,
    "memoryintfreekbs": -1,
    "memorykbs": 524288,
    "memorytargetkbs": 524288,
    "name": "user-vm-1",
    "networkkbsread": 0,
    "networkkbswrite": 0,
    "nic": [
      {
        "broadcasturi": "vlan://3757",
        "deviceid": "0",
        "extradhcpoption": [],
        "gateway": "10.1.1.1",
        "id": "135c61c2-5308-451f-82d1-022cf15e956e",
        "ipaddress": "10.1.1.189",
        "isdefault": true,
        "isolationuri": "vlan://3757",
        "macaddress": "02:01:00:cd:00:01",
        "netmask": "255.255.255.0",
        "networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
        "networkname": "user-network",
        "secondaryip": [],
        "traffictype": "Guest",
        "type": "Isolated"
      }
    ],
    "osdisplayname": "CentOS 5.5 (64-bit)",
    "ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "passwordenabled": false,
    "pooltype": "NetworkFilesystem",
    "readonlydetails": "dataDiskController, rootDiskController",
    "receivedbytes": 0,
    "rootdeviceid": 0,
    "rootdevicetype": "ROOT",
    "securitygroup": [],
    "sentbytes": 0,
    "serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
    "serviceofferingname": "Small Instance",
    "state": "Running",
    "tags": [],
    "templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templateformat": "QCOW2",
    "templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
    "templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templatetype": "BUILTIN",
    "userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
    "username": "user",
    "zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
    "zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
  }
}

Status: PASSED

TC2: Verify empty setting allows all VM detail modifications

Objective:
Core test - verify that clearing the user.vm.readonly.details setting allows regular users to modify all VM details including dataDiskController and rootDiskController.

Test Steps:

  1. As Root Admin, cleared user.vm.readonly.details setting (set to empty value)
  2. Verified database stores the value
  3. As regular User (ACSUser), attempted to modify dataDiskController detail on the VM
  4. As regular User (ACSUser), attempted to modify rootDiskController detail on the VM

Expected Result:

  • Setting should be cleared successfully
  • Both dataDiskController and rootDiskController modifications should be ALLOWED

Actual Result:

  • Setting was cleared successfully (API returns value: "", DB stores NULL)
  • Both modifications SUCCEEDED
  • Response shows readonlydetails: "" (empty)

Test Evidence:

  • Admin clears the setting
(localcloud) 🐱 > update configuration name=user.vm.readonly.details value=
{
  "configuration": {
    "category": "Advanced",
    "component": "QueryService",
    "defaultvalue": "dataDiskController, rootDiskController",
    "description": "List of read-only VM settings/details as comma separated string",
    "displaytext": "User vm readonly details",
    "group": "Compute",
    "isdynamic": true,
    "name": "user.vm.readonly.details",
    "subgroup": "Virtual Machine",
    "type": "CSV",
    "value": ""
  }
}
  • Database verification
mysql> SELECT name, value, default_value FROM configuration WHERE name='user.vm.readonly.details';
+--------------------------+-------+----------------------------------------+
| name                     | value | default_value                          |
+--------------------------+-------+----------------------------------------+
| user.vm.readonly.details | NULL  | dataDiskController, rootDiskController |
+--------------------------+-------+----------------------------------------+
1 row in set (0.00 sec)
  • User can now modify previously readonly details
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].dataDiskController=ide
{
  "virtualmachine": {
    "account": "ACSUser",
    "affinitygroup": [],
    "cpunumber": 1,
    "cpuspeed": 500,
    "cpuused": "11.86%",
    "created": "2026-01-26T07:37:11+0000",
    "deleteprotection": false,
    "details": {
      "dataDiskController": "ide"
    },
    "diskioread": 0,
    "diskiowrite": 4,
    "diskkbsread": 0,
    "diskkbswrite": 24,
    "displayname": "user-vm-1",
    "domain": "ROOT",
    "domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
    "domainpath": "/",
    "guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "haenable": false,
    "hasannotations": false,
    "hostcontrolstate": "Enabled",
    "hypervisor": "KVM",
    "id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
    "ipaddress": "10.1.1.189",
    "isdynamicallyscalable": false,
    "lastupdated": "2026-01-26T07:38:21+0000",
    "memory": 512,
    "memoryintfreekbs": -1,
    "memorykbs": 524288,
    "memorytargetkbs": 524288,
    "name": "user-vm-1",
    "networkkbsread": 0,
    "networkkbswrite": 0,
    "nic": [
      {
        "broadcasturi": "vlan://3757",
        "deviceid": "0",
        "extradhcpoption": [],
        "gateway": "10.1.1.1",
        "id": "135c61c2-5308-451f-82d1-022cf15e956e",
        "ipaddress": "10.1.1.189",
        "isdefault": true,
        "isolationuri": "vlan://3757",
        "macaddress": "02:01:00:cd:00:01",
        "netmask": "255.255.255.0",
        "networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
        "networkname": "user-network",
        "secondaryip": [],
        "traffictype": "Guest",
        "type": "Isolated"
      }
    ],
    "osdisplayname": "CentOS 5.5 (64-bit)",
    "ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "passwordenabled": false,
    "pooltype": "NetworkFilesystem",
    "readonlydetails": "",
    "receivedbytes": 0,
    "rootdeviceid": 0,
    "rootdevicetype": "ROOT",
    "securitygroup": [],
    "sentbytes": 0,
    "serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
    "serviceofferingname": "Small Instance",
    "state": "Running",
    "tags": [],
    "templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templateformat": "QCOW2",
    "templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
    "templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templatetype": "BUILTIN",
    "userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
    "username": "user",
    "zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
    "zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
  }
}
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].rootDiskController=ide
{
  "virtualmachine": {
    "account": "ACSUser",
    "affinitygroup": [],
    "cpunumber": 1,
    "cpuspeed": 500,
    "cpuused": "11.86%",
    "created": "2026-01-26T07:37:11+0000",
    "deleteprotection": false,
    "details": {
      "rootDiskController": "ide"
    },
    "diskioread": 0,
    "diskiowrite": 4,
    "diskkbsread": 0,
    "diskkbswrite": 24,
    "displayname": "user-vm-1",
    "domain": "ROOT",
    "domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
    "domainpath": "/",
    "guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "haenable": false,
    "hasannotations": false,
    "hostcontrolstate": "Enabled",
    "hypervisor": "KVM",
    "id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
    "ipaddress": "10.1.1.189",
    "isdynamicallyscalable": false,
    "lastupdated": "2026-01-26T07:38:21+0000",
    "memory": 512,
    "memoryintfreekbs": -1,
    "memorykbs": 524288,
    "memorytargetkbs": 524288,
    "name": "user-vm-1",
    "networkkbsread": 0,
    "networkkbswrite": 0,
    "nic": [
      {
        "broadcasturi": "vlan://3757",
        "deviceid": "0",
        "extradhcpoption": [],
        "gateway": "10.1.1.1",
        "id": "135c61c2-5308-451f-82d1-022cf15e956e",
        "ipaddress": "10.1.1.189",
        "isdefault": true,
        "isolationuri": "vlan://3757",
        "macaddress": "02:01:00:cd:00:01",
        "netmask": "255.255.255.0",
        "networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
        "networkname": "user-network",
        "secondaryip": [],
        "traffictype": "Guest",
        "type": "Isolated"
      }
    ],
    "osdisplayname": "CentOS 5.5 (64-bit)",
    "ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "passwordenabled": false,
    "pooltype": "NetworkFilesystem",
    "readonlydetails": "",
    "receivedbytes": 0,
    "rootdeviceid": 0,
    "rootdevicetype": "ROOT",
    "securitygroup": [],
    "sentbytes": 0,
    "serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
    "serviceofferingname": "Small Instance",
    "state": "Running",
    "tags": [],
    "templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templateformat": "QCOW2",
    "templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
    "templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templatetype": "BUILTIN",
    "userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
    "username": "user",
    "zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
    "zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
  }
}

Status: PASSED

TC3: Verify custom readonly details are enforced

Objective:
Confirm that custom values in the user.vm.readonly.details setting are properly enforced, blocking those specific details while allowing modification of previously default readonly details.

Test Steps:

  1. As Root Admin, set user.vm.readonly.details to custom value: customDetail1,customDetail2
  2. As regular User (ACSUser), attempted to modify customDetail1 on the VM
  3. As regular User (ACSUser), attempted to modify dataDiskController (previously default readonly, now allowed)

Expected Result:

  • customDetail1 modification should be BLOCKED
  • dataDiskController modification should be ALLOWED

Actual Result:

  • customDetail1 modification was BLOCKED with error 4250
  • dataDiskController modification SUCCEEDED
  • Response shows readonlydetails: "customDetail1,customDetail2"

Test Evidence:

(localcloud) 🐱 > update configuration name=user.vm.readonly.details value=customDetail1,customDetail2
{
  "configuration": {
    "category": "Advanced",
    "component": "QueryService",
    "defaultvalue": "dataDiskController, rootDiskController",
    "description": "List of read-only VM settings/details as comma separated string",
    "displaytext": "User vm readonly details",
    "group": "Compute",
    "isdynamic": true,
    "name": "user.vm.readonly.details",
    "subgroup": "Virtual Machine",
    "type": "CSV",
    "value": "customDetail1,customDetail2"
  }
}
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].customDetail1=test
🙈 Error: (HTTP 530, error code 4250) Internal error executing command, please contact your system administrator

(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].dataDiskController=virtio
{
  "virtualmachine": {
    "account": "ACSUser",
    "affinitygroup": [],
    "cpunumber": 1,
    "cpuspeed": 500,
    "cpuused": "11.77%",
    "created": "2026-01-26T07:37:11+0000",
    "deleteprotection": false,
    "details": {
      "dataDiskController": "virtio"
    },
    "diskioread": 0,
    "diskiowrite": 7,
    "diskkbsread": 0,
    "diskkbswrite": 40,
    "displayname": "user-vm-1",
    "domain": "ROOT",
    "domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
    "domainpath": "/",
    "guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "haenable": false,
    "hasannotations": false,
    "hostcontrolstate": "Enabled",
    "hypervisor": "KVM",
    "id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
    "ipaddress": "10.1.1.189",
    "isdynamicallyscalable": false,
    "lastupdated": "2026-01-26T07:38:21+0000",
    "memory": 512,
    "memoryintfreekbs": -1,
    "memorykbs": 524288,
    "memorytargetkbs": 524288,
    "name": "user-vm-1",
    "networkkbsread": 0,
    "networkkbswrite": 0,
    "nic": [
      {
        "broadcasturi": "vlan://3757",
        "deviceid": "0",
        "extradhcpoption": [],
        "gateway": "10.1.1.1",
        "id": "135c61c2-5308-451f-82d1-022cf15e956e",
        "ipaddress": "10.1.1.189",
        "isdefault": true,
        "isolationuri": "vlan://3757",
        "macaddress": "02:01:00:cd:00:01",
        "netmask": "255.255.255.0",
        "networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
        "networkname": "user-network",
        "secondaryip": [],
        "traffictype": "Guest",
        "type": "Isolated"
      }
    ],
    "osdisplayname": "CentOS 5.5 (64-bit)",
    "ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "passwordenabled": false,
    "pooltype": "NetworkFilesystem",
    "readonlydetails": "customDetail1,customDetail2",
    "receivedbytes": 0,
    "rootdeviceid": 0,
    "rootdevicetype": "ROOT",
    "securitygroup": [],
    "sentbytes": 0,
    "serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
    "serviceofferingname": "Small Instance",
    "state": "Running",
    "tags": [],
    "templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templateformat": "QCOW2",
    "templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
    "templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templatetype": "BUILTIN",
    "userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
    "username": "user",
    "zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
    "zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
  }
}

Status: PASSED

TC4: Verify Root Admin can always modify all details

Objective: Confirm that Root Admin can modify all VM details regardless of the user.vm.readonly.details setting, bypassing readonly restrictions.

Test Steps:

  1. As Root Admin, set user.vm.readonly.details back to default value: dataDiskController,rootDiskController
  2. As Root Admin, attempted to modify dataDiskController on admin-owned VM
  3. As Root Admin, attempted to modify rootDiskController on admin-owned VM

Expected Result: Both modifications should SUCCEED (Root Admin bypasses readonly restrictions)

Actual Result:

  • Both modifications SUCCEEDED
  • Root Admin can modify all details regardless of readonly setting

Test Evidence:

(localcloud) 🐱 > update configuration name=user.vm.readonly.details value=dataDiskController,rootDiskController
{
  "configuration": {
    "category": "Advanced",
    "component": "QueryService",
    "defaultvalue": "dataDiskController, rootDiskController",
    "description": "List of read-only VM settings/details as comma separated string",
    "displaytext": "User vm readonly details",
    "group": "Compute",
    "isdynamic": true,
    "name": "user.vm.readonly.details",
    "subgroup": "Virtual Machine",
    "type": "CSV",
    "value": "dataDiskController,rootDiskController"
  }
}
(localcloud) 🐱 > update virtualmachine id=5114fc96-b48a-40ab-ae17-dd896de35921 details[0].dataDiskController=virtio
{
  "virtualmachine": {
    "account": "admin",
    "affinitygroup": [],
    "arch": "x86_64",
    "cpunumber": 1,
    "cpuspeed": 500,
    "cpuused": "11.66%",
    "created": "2026-01-26T07:31:57+0000",
    "deleteprotection": false,
    "details": {
      "dataDiskController": "virtio"
    },
    "diskioread": 0,
    "diskiowrite": 4,
    "diskkbsread": 0,
    "diskkbswrite": 24,
    "displayname": "test-vm-1",
    "displayvm": true,
    "domain": "ROOT",
    "domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
    "domainpath": "/",
    "guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "haenable": false,
    "hasannotations": false,
    "hostcontrolstate": "Enabled",
    "hostid": "f3453c9a-ecf5-45fd-aa3d-dd00554f357a",
    "hostname": "ref-trl-10709-k-Mol9-rositsa-kyuchukova-kvm1",
    "hypervisor": "KVM",
    "id": "5114fc96-b48a-40ab-ae17-dd896de35921",
    "instancename": "i-2-4-VM",
    "ipaddress": "10.1.1.58",
    "isdynamicallyscalable": false,
    "lastupdated": "2026-01-26T07:33:13+0000",
    "memory": 512,
    "memoryintfreekbs": -1,
    "memorykbs": 524288,
    "memorytargetkbs": 524288,
    "name": "test-vm-1",
    "networkkbsread": 0,
    "networkkbswrite": 0,
    "nic": [
      {
        "broadcasturi": "vlan://3755",
        "deviceid": "0",
        "extradhcpoption": [],
        "gateway": "10.1.1.1",
        "id": "5e176490-5150-4a73-bae7-6a58cd8e4284",
        "ipaddress": "10.1.1.58",
        "isdefault": true,
        "isolationuri": "vlan://3755",
        "macaddress": "02:01:00:cc:00:01",
        "netmask": "255.255.255.0",
        "networkid": "967e918d-ef94-45f5-9678-650ccedb414f",
        "networkname": "test-network",
        "secondaryip": [],
        "traffictype": "Guest",
        "type": "Isolated"
      }
    ],
    "osdisplayname": "CentOS 5.5 (64-bit)",
    "ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "passwordenabled": false,
    "pooltype": "NetworkFilesystem",
    "receivedbytes": 0,
    "rootdeviceid": 0,
    "rootdevicetype": "ROOT",
    "securitygroup": [],
    "sentbytes": 0,
    "serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
    "serviceofferingname": "Small Instance",
    "state": "Running",
    "tags": [],
    "templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templateformat": "QCOW2",
    "templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
    "templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templatetype": "BUILTIN",
    "userid": "8df43f1b-f87c-11f0-83e5-1e0020000324",
    "username": "admin",
    "zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
    "zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
  }
}
(localcloud) 🐱 > update virtualmachine id=5114fc96-b48a-40ab-ae17-dd896de35921 details[0].rootDiskController=virtio
{
  "virtualmachine": {
    "account": "admin",
    "affinitygroup": [],
    "arch": "x86_64",
    "cpunumber": 1,
    "cpuspeed": 500,
    "cpuused": "11.66%",
    "created": "2026-01-26T07:31:57+0000",
    "deleteprotection": false,
    "details": {
      "rootDiskController": "virtio"
    },
    "diskioread": 0,
    "diskiowrite": 4,
    "diskkbsread": 0,
    "diskkbswrite": 24,
    "displayname": "test-vm-1",
    "displayvm": true,
    "domain": "ROOT",
    "domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
    "domainpath": "/",
    "guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "haenable": false,
    "hasannotations": false,
    "hostcontrolstate": "Enabled",
    "hostid": "f3453c9a-ecf5-45fd-aa3d-dd00554f357a",
    "hostname": "ref-trl-10709-k-Mol9-rositsa-kyuchukova-kvm1",
    "hypervisor": "KVM",
    "id": "5114fc96-b48a-40ab-ae17-dd896de35921",
    "instancename": "i-2-4-VM",
    "ipaddress": "10.1.1.58",
    "isdynamicallyscalable": false,
    "lastupdated": "2026-01-26T07:33:13+0000",
    "memory": 512,
    "memoryintfreekbs": -1,
    "memorykbs": 524288,
    "memorytargetkbs": 524288,
    "name": "test-vm-1",
    "networkkbsread": 0,
    "networkkbswrite": 0,
    "nic": [
      {
        "broadcasturi": "vlan://3755",
        "deviceid": "0",
        "extradhcpoption": [],
        "gateway": "10.1.1.1",
        "id": "5e176490-5150-4a73-bae7-6a58cd8e4284",
        "ipaddress": "10.1.1.58",
        "isdefault": true,
        "isolationuri": "vlan://3755",
        "macaddress": "02:01:00:cc:00:01",
        "netmask": "255.255.255.0",
        "networkid": "967e918d-ef94-45f5-9678-650ccedb414f",
        "networkname": "test-network",
        "secondaryip": [],
        "traffictype": "Guest",
        "type": "Isolated"
      }
    ],
    "osdisplayname": "CentOS 5.5 (64-bit)",
    "ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "passwordenabled": false,
    "pooltype": "NetworkFilesystem",
    "receivedbytes": 0,
    "rootdeviceid": 0,
    "rootdevicetype": "ROOT",
    "securitygroup": [],
    "sentbytes": 0,
    "serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
    "serviceofferingname": "Small Instance",
    "state": "Running",
    "tags": [],
    "templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templateformat": "QCOW2",
    "templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
    "templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templatetype": "BUILTIN",
    "userid": "8df43f1b-f87c-11f0-83e5-1e0020000324",
    "username": "admin",
    "zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
    "zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
  }
}

Status: PASSED

TC5: Verify workaround still works (bogus value)

Objective: Confirm that the existing workaround of setting a bogus/non-existent value in user.vm.readonly.details still functions, allowing users to modify dataDiskController and rootDiskController.

Test Steps:

  1. As Root Admin, set user.vm.readonly.details to bogusNonExistentDetail
  2. As regular User (ACSUser), attempted to modify dataDiskController on the VM
  3. As regular User (ACSUser), attempted to modify rootDiskController on the VM

Expected Result: Both modifications should SUCCEED (bogus value doesn't match real details)

Actual Result:

  • Both modifications SUCCEEDED
  • Response shows readonlydetails: "bogusNonExistentDetail"

Test Evidence:

(localcloud) 🐱 > update configuration name=user.vm.readonly.details value=bogusNonExistentDetail
{
  "configuration": {
    "category": "Advanced",
    "component": "QueryService",
    "defaultvalue": "dataDiskController, rootDiskController",
    "description": "List of read-only VM settings/details as comma separated string",
    "displaytext": "User vm readonly details",
    "group": "Compute",
    "isdynamic": true,
    "name": "user.vm.readonly.details",
    "subgroup": "Virtual Machine",
    "type": "CSV",
    "value": "bogusNonExistentDetail"
  }
}

(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].dataDiskController=osdefault
{
  "virtualmachine": {
    "account": "ACSUser",
    "affinitygroup": [],
    "cpunumber": 1,
    "cpuspeed": 500,
    "cpuused": "11.81%",
    "created": "2026-01-26T07:37:11+0000",
    "deleteprotection": false,
    "details": {
      "dataDiskController": "osdefault"
    },
    "diskioread": 0,
    "diskiowrite": 4,
    "diskkbsread": 0,
    "diskkbswrite": 24,
    "displayname": "user-vm-1",
    "domain": "ROOT",
    "domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
    "domainpath": "/",
    "guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "haenable": false,
    "hasannotations": false,
    "hostcontrolstate": "Enabled",
    "hypervisor": "KVM",
    "id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
    "ipaddress": "10.1.1.189",
    "isdynamicallyscalable": false,
    "lastupdated": "2026-01-26T07:38:21+0000",
    "memory": 512,
    "memoryintfreekbs": -1,
    "memorykbs": 524288,
    "memorytargetkbs": 524288,
    "name": "user-vm-1",
    "networkkbsread": 0,
    "networkkbswrite": 0,
    "nic": [
      {
        "broadcasturi": "vlan://3757",
        "deviceid": "0",
        "extradhcpoption": [],
        "gateway": "10.1.1.1",
        "id": "135c61c2-5308-451f-82d1-022cf15e956e",
        "ipaddress": "10.1.1.189",
        "isdefault": true,
        "isolationuri": "vlan://3757",
        "macaddress": "02:01:00:cd:00:01",
        "netmask": "255.255.255.0",
        "networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
        "networkname": "user-network",
        "secondaryip": [],
        "traffictype": "Guest",
        "type": "Isolated"
      }
    ],
    "osdisplayname": "CentOS 5.5 (64-bit)",
    "ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "passwordenabled": false,
    "pooltype": "NetworkFilesystem",
    "readonlydetails": "bogusNonExistentDetail",
    "receivedbytes": 0,
    "rootdeviceid": 0,
    "rootdevicetype": "ROOT",
    "securitygroup": [],
    "sentbytes": 0,
    "serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
    "serviceofferingname": "Small Instance",
    "state": "Running",
    "tags": [],
    "templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templateformat": "QCOW2",
    "templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
    "templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templatetype": "BUILTIN",
    "userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
    "username": "user",
    "zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
    "zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
  }
}

(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].rootDiskController=osdefault
{
  "virtualmachine": {
    "account": "ACSUser",
    "affinitygroup": [],
    "cpunumber": 1,
    "cpuspeed": 500,
    "cpuused": "11.81%",
    "created": "2026-01-26T07:37:11+0000",
    "deleteprotection": false,
    "details": {
      "rootDiskController": "osdefault"
    },
    "diskioread": 0,
    "diskiowrite": 4,
    "diskkbsread": 0,
    "diskkbswrite": 24,
    "displayname": "user-vm-1",
    "domain": "ROOT",
    "domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
    "domainpath": "/",
    "guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "haenable": false,
    "hasannotations": false,
    "hostcontrolstate": "Enabled",
    "hypervisor": "KVM",
    "id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
    "ipaddress": "10.1.1.189",
    "isdynamicallyscalable": false,
    "lastupdated": "2026-01-26T07:38:21+0000",
    "memory": 512,
    "memoryintfreekbs": -1,
    "memorykbs": 524288,
    "memorytargetkbs": 524288,
    "name": "user-vm-1",
    "networkkbsread": 0,
    "networkkbswrite": 0,
    "nic": [
      {
        "broadcasturi": "vlan://3757",
        "deviceid": "0",
        "extradhcpoption": [],
        "gateway": "10.1.1.1",
        "id": "135c61c2-5308-451f-82d1-022cf15e956e",
        "ipaddress": "10.1.1.189",
        "isdefault": true,
        "isolationuri": "vlan://3757",
        "macaddress": "02:01:00:cd:00:01",
        "netmask": "255.255.255.0",
        "networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
        "networkname": "user-network",
        "secondaryip": [],
        "traffictype": "Guest",
        "type": "Isolated"
      }
    ],
    "osdisplayname": "CentOS 5.5 (64-bit)",
    "ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "passwordenabled": false,
    "pooltype": "NetworkFilesystem",
    "readonlydetails": "bogusNonExistentDetail",
    "receivedbytes": 0,
    "rootdeviceid": 0,
    "rootdevicetype": "ROOT",
    "securitygroup": [],
    "sentbytes": 0,
    "serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
    "serviceofferingname": "Small Instance",
    "state": "Running",
    "tags": [],
    "templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templateformat": "QCOW2",
    "templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
    "templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templatetype": "BUILTIN",
    "userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
    "username": "user",
    "zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
    "zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
  }
}

Status: PASSED

TC6: Verify setting change persists across MS restart

Objective: Confirm that the empty value for user.vm.readonly.details persists after management server restart and the fix continues to work.

Test Steps:

  1. As Root Admin, set user.vm.readonly.details to empty value
  2. Verified database stores the value (NULL)
  3. Restarted management server
  4. Verified MS is running after restart
  5. Verified setting is still empty via API
  6. As regular User (ACSUser), attempted to modify dataDiskController on the VM

Expected Result:

  • Setting should persist as empty after restart
  • VM detail modification should SUCCEED

Actual Result:

  • Setting persisted after MS restart
  • VM detail modification SUCCEEDED
  • Response shows readonlydetails: ""

Test Evidence:

  • Before restart - set empty value
(localcloud) 🐱 > update configuration name=user.vm.readonly.details value=
{
  "configuration": {
    "category": "Advanced",
    "component": "QueryService",
    "defaultvalue": "dataDiskController, rootDiskController",
    "description": "List of read-only VM settings/details as comma separated string",
    "displaytext": "User vm readonly details",
    "group": "Compute",
    "isdynamic": true,
    "name": "user.vm.readonly.details",
    "subgroup": "Virtual Machine",
    "type": "CSV",
    "value": ""
  }
}
  • Database verification before restart
mysql> SELECT name, value, default_value FROM configuration WHERE name='user.vm.readonly.details';
+--------------------------+-------+----------------------------------------+
| name                     | value | default_value                          |
+--------------------------+-------+----------------------------------------+
| user.vm.readonly.details | NULL  | dataDiskController, rootDiskController |
+--------------------------+-------+----------------------------------------+
1 row in set (0.00 sec)
  • MS restart
[root@ref-trl-10709-k-Mol9-rositsa-kyuchukova-mgmt1 ~]# systemctl restart cloudstack-management && sleep 60 && systemctl status cloudstack-management | head -10
● cloudstack-management.service - CloudStack Management Server
     Loaded: loaded (/usr/lib/systemd/system/cloudstack-management.service; enabled; vendor preset: disabled)
    Drop-In: /etc/systemd/system/cloudstack-management.service.d
             └─filelimit.conf
     Active: active (running) since Mon 2026-01-26 07:59:08 UTC; 1min 0s ago
   Main PID: 210700 (java)
      Tasks: 214 (limit: 31170)
     Memory: 1.0G
        CPU: 1min 17.820s
     CGroup: /system.slice/cloudstack-management.service
  • After restart - verify setting persists
(localcloud) 🐱 > list configurations name=user.vm.readonly.details
{
  "configuration": [
    {
      "category": "Advanced",
      "component": "QueryService",
      "defaultvalue": "dataDiskController, rootDiskController",
      "description": "List of read-only VM settings/details as comma separated string",
      "displaytext": "User vm readonly details",
      "group": "Compute",
      "isdynamic": true,
      "name": "user.vm.readonly.details",
      "subgroup": "Virtual Machine",
      "type": "CSV"
    }
  ],
  "count": 1
}
  • User can still modify previously readonly details after restart
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].dataDiskController=scsi
{
  "virtualmachine": {
    "account": "ACSUser",
    "affinitygroup": [],
    "cpunumber": 1,
    "cpuspeed": 500,
    "cpuused": "12.17%",
    "created": "2026-01-26T07:37:11+0000",
    "deleteprotection": false,
    "details": {
      "dataDiskController": "scsi"
    },
    "diskioread": 0,
    "diskiowrite": 9,
    "diskkbsread": 0,
    "diskkbswrite": 56,
    "displayname": "user-vm-1",
    "domain": "ROOT",
    "domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
    "domainpath": "/",
    "guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "haenable": false,
    "hasannotations": false,
    "hostcontrolstate": "Enabled",
    "hypervisor": "KVM",
    "id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
    "ipaddress": "10.1.1.189",
    "isdynamicallyscalable": false,
    "lastupdated": "2026-01-26T07:38:21+0000",
    "memory": 512,
    "memoryintfreekbs": -1,
    "memorykbs": 524288,
    "memorytargetkbs": 524288,
    "name": "user-vm-1",
    "networkkbsread": 0,
    "networkkbswrite": 0,
    "nic": [
      {
        "broadcasturi": "vlan://3757",
        "deviceid": "0",
        "extradhcpoption": [],
        "gateway": "10.1.1.1",
        "id": "135c61c2-5308-451f-82d1-022cf15e956e",
        "ipaddress": "10.1.1.189",
        "isdefault": true,
        "isolationuri": "vlan://3757",
        "macaddress": "02:01:00:cd:00:01",
        "netmask": "255.255.255.0",
        "networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
        "networkname": "user-network",
        "secondaryip": [],
        "traffictype": "Guest",
        "type": "Isolated"
      }
    ],
    "osdisplayname": "CentOS 5.5 (64-bit)",
    "ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
    "passwordenabled": false,
    "pooltype": "NetworkFilesystem",
    "readonlydetails": "",
    "receivedbytes": 0,
    "rootdeviceid": 0,
    "rootdevicetype": "ROOT",
    "securitygroup": [],
    "sentbytes": 0,
    "serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
    "serviceofferingname": "Small Instance",
    "state": "Running",
    "tags": [],
    "templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templateformat": "QCOW2",
    "templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
    "templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
    "templatetype": "BUILTIN",
    "userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
    "username": "user",
    "zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
    "zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
  }
}

Status: PASSED

@borisstoyanov borisstoyanov marked this pull request as ready for review January 26, 2026 08:13
Copilot AI review requested due to automatic review settings January 26, 2026 08:13
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes issue #10305 where clearing the user.vm.readonly.details global setting causes it to revert to default values instead of allowing all VM details to be modified. The fix introduces a new optional defaultValueIfEmpty parameter to the ConfigKey class that allows specifying a distinct value when a configuration is explicitly set to empty string, as opposed to being null or using the default value.

Changes:

  • Added defaultValueIfEmpty field and constructor parameter to ConfigKey class to handle empty string configurations differently from null/default values
  • Modified value() and valueInScope() methods to check for empty string values and use defaultValueIfEmpty when appropriate
  • Updated UserVMReadOnlyDetails ConfigKey to use empty string as defaultValueIfEmpty, allowing users to clear all readonly restrictions

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigKey.java Added new field, constructor overload, and logic to handle empty string configurations distinctly from null values
api/src/main/java/org/apache/cloudstack/query/QueryService.java Updated UserVMReadOnlyDetails to pass empty string as defaultValueIfEmpty parameter

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +129 to +133
public ConfigKey(Class<T> type, String name, String category, String defaultValue, String description, boolean isDynamic, Scope scope, T multiplier,
String displayText, String parent, Ternary<String, String, Long> group, Pair<String, Long> subGroup, Kind kind, String options, String defaultValueIfEmpty) {
this(type, name, category, defaultValue, description, isDynamic, scope, multiplier, displayText, parent, group, subGroup, kind, options);
this._defaultValueIfEmpty = defaultValueIfEmpty;
}
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding JavaDoc documentation for this new constructor to explain the purpose and usage of the defaultValueIfEmpty parameter. This would help other developers understand when and why to use this constructor variant.

Copilot uses AI. Check for mistakes.
T _value = null;

static ConfigDepotImpl s_depot = null;

Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding JavaDoc documentation for the new _defaultValueIfEmpty field to explain its purpose. This field represents the value to use when the configuration is explicitly set to empty string, as opposed to using the default value. This distinction is important for understanding the behavior when users clear a configuration value.

Suggested change
/**
* Alternative default value used when the configuration value is explicitly set
* to the empty string. This allows distinguishing between:
* <ul>
* <li>a missing or unset configuration value, which uses {@link #_defaultValue}, and</li>
* <li>a configuration value explicitly cleared to "", which uses this value instead.</li>
* </ul>
*/

Copilot uses AI. Check for mistakes.
@borisstoyanov borisstoyanov merged commit 4adb719 into 4.20 Jan 26, 2026
29 of 31 checks passed
@sureshanaparti sureshanaparti deleted the readonly-vm-details-empty branch January 26, 2026 10:10
DaanHoogland pushed a commit that referenced this pull request Jan 26, 2026
* 4.22:
  fix install path for systemvm templates when introducing new sec storage (#11605)
  fix Sensitive Data Exposure Through Exception Logging in OVM Hypervis… (#12032)
  Fix snapshot physical size after migration (#12166)
  ConfigDrive: use file absolute path instead of canonical path to create ISO (#11623)
  Add log for null templateVO (#12406)
  snapshot: fix listSnapshots for volume which got delete and whose storage pool got deleted (#12433)
  Notify user if template upgrade is not required (#12483)
  Fix: proper permissions for systemvm template registrations on hardened systems (#12098)
  Allow modification of user vm details if user.vm.readonly.details is empty (#10456)
  NPE fix while deleting storage pool when pool has detached volumes (#12451)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Blank value in 'user.vm.readonly.details' uses default values

9 participants